package com.blockchainenergy.common;

import com.blockchainenergy.blockChain.DataBlock;
import com.blockchainenergy.blockChain.DataChain;
import com.blockchainenergy.blockChain.Carbon;
import com.blockchainenergy.info.line.LineWastage;
import com.blockchainenergy.info.node.NodeFlow;
import com.blockchainenergy.info.node.NodePower;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class CarbonTools {

    public static List<DataBlock> add(int i, int previous, double p, double e, double flow) throws Exception {
        DataChain dataChain = DataChain.getInstance();
        dataChain.newCarbonBlock(new Carbon(i, previous, p, e, flow));
        return dataChain.getChain();
    }

    /*
     * 第n个区块 下标为n的区块
     * 0 1 2 3 4 5
     * */
    public static int outputi(int n) throws Exception {
        return DataChain.getInstance().getChain().get(n).getCarbon().getI();
    }

    public static int outputj(int n) throws Exception {
        return DataChain.getInstance().getChain().get(n).getCarbon().getPrevious();
    }

    public static double outputp(int n) throws Exception {
        return DataChain.getInstance().getChain().get(n).getCarbon().getP();
    }

    public static double outpute(int n) throws Exception {
        return DataChain.getInstance().getChain().get(n).getCarbon().getE();
    }

    public static double outputn(int n) throws Exception {
        return DataChain.getInstance().getChain().get(n).getCarbon().getFlow();
    }

    public static int getNmax() throws Exception {
        return DataChain.getInstance().getChain().size() - 1;
    }


    public static void singlecalculation() throws Exception {
        int nmax = getNmax();

        double power[] = new double[1069];
        for (int count = 0; count < 1069; count++) {
            power[count] = 0;
        }
        for (int i = 1; i <= 33; i++)
        //这一部分是2
        {
            for (int j = 1; j <= 33; j++) {
                for (int countn = nmax; countn > 0; countn--) {
                    int temp_i = outputi(countn);
                    int temp_j = outputj(countn);
                    double temp_p = outputp(countn);
                    double temp_e = outpute(countn);
                    double temp_n = outputn(countn);
                    if (temp_i == i && temp_j == j && temp_p != -1 && temp_p != -2 && temp_e == 0 && temp_n == 0) {
                        power[33 * (i - 1) + j - 1] = temp_p;
                    }
                }
            }
        }


        int[] currentn = new int[33];
        //这个是currentn[i]表示第i个节点的级数
        for (int tempi = 1; tempi <= 33; tempi++) {
            currentn[tempi] = -1;
            int flag = 1;
            for (int tempj = 1; tempj <= 33; tempj++) {
                if (power[33 * (tempi - 1) + tempj - 1] < 0) {
                    flag = 0;
                }
            }
            if (flag == 1) {
                currentn[tempi] = 1;
            }
        }
        for (int node_n = 2; node_n <= 33; node_n++) {
            for (int i = 1; i <= 33; i++) {
                if (currentn[i - 1] == node_n - 1) {
                    for (int j = 1; j <= 33; j++) {
                        if (power[33 * (i - 1) + j - 1] > 0 && currentn[j - 1] == -1) {
                            currentn[j - 1] = node_n;
                        }
                    }
                }
            }
            for (int i = 1; i <= 33; i++) {
                if (currentn[i - 1] == node_n) {
                    int flag = 1;
                    for (int j = 1; j <= 33; j++) {
                        if (power[33 * (j - 1) + i - 1] > 0 && (currentn[j - 1] == node_n || currentn[j - 1] == -1)) {
                            flag = 0;
                        }
                    }
                    if (flag == 0) {
                        currentn[i - 1] = -1;
                    }
                }
            }
        }


        int jilu[];
        jilu = new int[33];
        for (int i = 0; i < 33; i++) {
            jilu[i] = currentn[i];
        }
        int currentshunxu[];
        currentshunxu = new int[33];
        for (int i = 0; i < 33; i++) {
            currentshunxu[i] = i + 1;
        }
        //这个是将节点按级数排好的矩阵
        for (int i = 0; i < 33; i++) {
            for (int j = 33; j > i; j--) {
                if (jilu[j] > jilu[j - 1]) {
                    int tempa = jilu[j];
                    jilu[j] = jilu[j - 1];
                    jilu[j - 1] = tempa;
                    int tempb = currentshunxu[j];
                    currentshunxu[j] = currentshunxu[j - 1];
                    currentshunxu[j - 1] = tempb;
                }
            }
        }


        for (int tt = 1; tt <= 33; tt++)
        //这一部分是4567
        {
            double sumpe = 0;
            double sump = 0;
            int tempi = currentshunxu[tt - 1];
            int isjjd[];
            isjjd = new int[33];
            int isjddcount = 0;
            for (int count = 0; count < 33; count++) {
                isjjd[count] = -1;
            }
            for (int previousj = 1; previousj <= 33; previousj++) {
                if (power[33 * (previousj - 1) + tempi - 1] > 0) {
                    isjjd[isjddcount] = previousj;
                    isjddcount++;
                }
            }
            double[] isje = new double[33];
            for (int count = 0; count < 33; count++) {
                isje[count] = -1;
            }
            for (int tc = 0; tc < 33; tc++) {
                int tempe = isjjd[tc];
                if (tempe != -1) {
                    for (int countn = nmax; countn > 0; countn++) {
                        int temp_i = outputi(countn);
                        int temp_j = outputj(countn);
                        double temp_p = outputp(countn);
                        double temp_e = outpute(countn);
                        double temp_n = outputn(countn);
                        if (temp_i == tempe && temp_j == tempe && temp_p == -1 && temp_n == 0) {
                            isje[tempe] = temp_e;
                        }
                    }
                    double temp_pe = power[33 * (tempe - 1) + tempi - 1] * isje[tempe];
                    sumpe += temp_pe;
                    double temp_p = power[33 * (tempe - 1) + tempi - 1];
                    sump += temp_p;
                }
            }
            if (sump != 0) {
                double currente = sumpe / sump;
                add(tempi, tempi, -1, currente, 0);
                for (int a = 1; a <= 33; a++) {
                    double atemp = currente * power[33 * (tempi - 1) + a - 1];
                    add(tempi, a, -2, 0, atemp);
                }
            } else {
                add(tempi, tempi, -1, 0, 0);
                for (int a = 1; a <= 33; a++) {
                    add(tempi, a, -2, 0, 0);
                }
            }
        }
    }


    public static int recognize_block_type(int n) throws Exception {
        int temp_i = outputi(n);
        int temp_j = outputj(n);
        double temp_p = outputp(n);
        double temp_e = outpute(n);
        double temp_n = outputn(n);
        if (temp_p != -1 && temp_p != -2 && temp_n == 0) {
            return 1;
        } else if (temp_i == temp_j && temp_p == -1 && temp_n == 0) {
            return 2;
        } else if (temp_p == -2 && temp_e == 0 && temp_n == 0) {
            return 3;
        } else {
            return 0;
        }
    }

    public static double[] get_carbon_flow_record(int index) throws Exception {
        double[] a = new double[7];
        for (int i = 0; i < 7; i++) {
            a[i] = 0;
        }
        int n = getNmax();
        for (int count = 7; count > 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == index && temp_j == 1 && temp_p == -2 && temp_e == 0) {
                    double tempsum = 0;
                    for (int c = 1; c <= 33; c++) {
                        tempsum += outputn(n + c - 1);
                    }
                    a[count - 1] = tempsum;
                }
                n--;
            }
        }
        return a;
    }

    public static double[] get_carbon_potential_record(int index) throws Exception {
        double[] a = new double[8];
        int n = getNmax();
        for (int count = 7; count >= 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == temp_j && temp_j == index && temp_p == -1 && temp_n == 0) {
                    a[count] = temp_e;
                }
                n--;
            }
        }
        return a;
    }

    public static double get_recent_flow_total(int i) throws Exception {
        double[] a = get_carbon_flow_record(i);
        return a[6];
    }

    public static double currente(int i) throws Exception {
        double[] a = get_carbon_potential_record(i);
        return a[6];
    }

    public static int rrank(int i) throws Exception {
        double temp = get_recent_flow_total(i);
        double result = temp;
        if (temp < 0) {
            result = (-1) * temp;
        }
        if (result < 10000) {
            return 1;
        } else if (result >= 10000 && result < 100000) {
            return 2;
        } else {
            return 3;
        }
    }

    public static int erank(int i) throws Exception {
        double[] temp = get_carbon_potential_record(i);
        double result = temp[temp.length - 1];
        if (result < 0) {
            result = (-1) * result;
        }
        if (result <= 10) {
            return 1;
        } else if (result > 10 && result < 50) {
            return 2;
        } else {
            return 3;
        }
    }

    public static Double[] inflow(int index) throws Exception {
        Double[] a = new Double[8];
        for (int i = 0; i < 8; i++) {
            a[i] = 0D;
        }
        int n = getNmax();
        for (int count = 8; count > 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == index && temp_j == 1 && temp_p == -2 && temp_e == 0) {
                    double tempsum = 0;
                    for (int c = 1; c <= 33; c++) {
                        if (outputn(n + c - 1) < 0) {
                            tempsum += outputn(n + c - 1);
                        }
                    }
                    a[count - 1] = (-1) * tempsum;
                }
                n--;
            }
        }
        return a;
    }

    public static Double[] outflow(int index) throws Exception {
        Double[] a = new Double[8];
        for (int i = 0; i < 8; i++) {
            a[i] = 0D;
        }
        int n = getNmax();
        for (int count = 8; count > 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == index && temp_j == 1 && temp_p == -2 && temp_e == 0) {
                    double tempsum = 0;
                    for (int c = 1; c <= 33; c++) {
                        if (outputn(n + c - 1) >= 0) {
                            tempsum += outputn(n + c - 1);
                        }
                    }
                    a[count - 1] = tempsum;
                }
                n--;
            }
        }
        return a;
    }

    public static int derection(int i, int j) throws Exception {
        for (int n = getNmax(); n > 0; n--) {
            int temp_i = outputi(n);
            int temp_j = outputj(n);
            double temp_p = outputp(n);
            double temp_e = outpute(n);
            double temp_n = outputn(n);
            if (temp_i == i && temp_j == j && temp_p != -1 && temp_p != -2) {
                if (temp_p >= 0) {
                    return 1;
                } else {
                    return 2;
                }
            }
        }
        return 0;
    }

    public static double get_current_power(int i, int j) throws Exception {
        int flag = 1;
        double result = 0D;
        for (int n = getNmax(); n > 0 && flag == 1; n--) {
            int temp_i = outputi(n);
            int temp_j = outputj(n);
            double temp_p = outputp(n);
            double temp_e = outpute(n);
            double temp_n = outputn(n);
            if (temp_i == i && temp_j == j && temp_p != -1 && temp_p != -2) {
                result = temp_p;
                flag = 0;
            }
        }
        return result;
    }

    public static double get_current_flow(int i, int j) throws Exception {
        int flag = 1;
        double result = 0D;
        for (int n = getNmax(); n > 0 && flag == 1; n--) {
            int temp_i = outputi(n);
            int temp_j = outputj(n);
            double temp_p = outputp(n);
            double temp_e = outpute(n);
            double temp_n = outputn(n);
            if (temp_i == i && temp_j == j && temp_p == -2) {
                result = temp_n;
                flag = 0;
            }
        }
        return result;
    }


    public static Double[] inpower(int index) throws Exception {
        Double[] a = new Double[8];
        for (int i = 0; i < 8; i++) {
            a[i] = 0D;
        }
        int n = getNmax();
        for (int count = 8; count > 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == index && temp_j == 1 && temp_p != -1 && temp_p != -2) {
                    double tempsum = 0;
                    for (int c = 1; c <= 33; c++) {
                        if (outputp(n + c - 1) < 0) {
                            tempsum += outputp(n + c - 1);
                        }
                    }
                    a[count - 1] = (-1) * tempsum;
                }
                n--;
            }
        }
        return a;
    }

    public static Double[] outpower(int index) throws Exception {
        Double[] a = new Double[8];
        for (int i = 0; i < 8; i++) {
            a[i] = 0D;
        }
        int n = getNmax();
        for (int count = 8; count > 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == index && temp_j == 1 && temp_p != -1 && temp_p != -2) {
                    double tempsum = 0;
                    for (int c = 1; c <= 33; c++) {
                        if (outputp(n + c - 1) >= 0) {
                            tempsum += outputp(n + c - 1);
                        }
                    }
                    a[count - 1] = tempsum;
                }
                n--;
            }
        }
        return a;
    }

    public static List<NodePower> currentpower(int i) throws Exception {
        List<NodePower> res = new ArrayList<>();
        for (int j = 0; j < 33; j++) {
            NodePower nodePower = new NodePower();
            double temp_p = get_current_power(i, j);
            if (temp_p != 0) {
                nodePower.setI(j + 1);
                if (temp_p > 0) {
                    nodePower.setInOrOut(1);
                    nodePower.setPower((-1) * temp_p);
                } else {
                    nodePower.setInOrOut(2);
                    nodePower.setPower(temp_p);
                }
            }
            res.add(nodePower);
        }
        return res;
    }

    public static Double[] recordflow(int i) throws Exception {
        Double[] a = inflow(i);
        Double[] b = outflow(i);
        Double[] result = new Double[8];
        for (int j = 0; j < 8; j++) {
            result[j] = b[j] - a[j];
        }
        return result;
    }

    public static List<NodeFlow> currentflow(int i) throws Exception {
        List<NodeFlow> res = new ArrayList<>();
        for (int j = 0; j < 33; j++) {
            NodeFlow nodeFlow = new NodeFlow();
            double temp_n = get_current_flow(i, j);
            if (temp_n != 0) {
                nodeFlow.setI(j + 1);
                if (temp_n > 0) {
                    nodeFlow.setInOrOut(2);
                    nodeFlow.setFlow(temp_n);
                } else {
                    nodeFlow.setInOrOut(1);
                    nodeFlow.setFlow((-1) * temp_n);
                }
            }
            res.add(nodeFlow);
        }
        return res;
    }

    public static Double[] routeflow(int i, int j) throws Exception {
        Double result[] = new Double[8];
        Arrays.fill(result, 0D);
        int n = getNmax();
        for (int count = 8; count > 0; count--) {
            while (n > 0) {
                int temp_i = outputi(n);
                int temp_j = outputj(n);
                double temp_p = outputp(n);
                double temp_e = outpute(n);
                double temp_n = outputn(n);
                if (temp_i == i && temp_j == j && temp_p == -2) {
                    result[count - 1] = temp_n;
                }
                n--;
            }
        }
        return result;
    }

    public static Double[] routeinflow(int i, int j) throws Exception {
        Double result[] = new Double[8];
        for (int count = 7; count >= 0; count--) {
            Double[] temp = routeflow(i, j);
            if (temp[count] >= 0) {
                result[count] = temp[count];
            } else {
                temp = routeflow(j, i);
                result[count] = temp[count];
            }
        }
        return result;
    }

    public static Double[] routeoutflow(int i, int j) throws Exception {
        Double result[] = new Double[8];
        Arrays.fill(result, 0D);
        for (int count = 7; count > 0; count--) {
            Double[] temp = routeflow(i, j);
            if (temp[count] < 0) {
                result[count] = temp[count];
            } else {
                temp = routeflow(j, i);
                result[count] = temp[count];
            }
        }
        for (int p = 0; p < result.length; p++) {
            result[p] = result[p] * -1;
        }
        return result;
    }

    public static List<LineWastage> currentwastage() throws Exception {
        double[][] result = new double[][]{{1, 2, 0}, {2, 19, 0}, {19, 20, 0}, {20, 21, 0}, {21, 22, 0}, {2, 3, 0}, {3, 23, 0}, {23, 24, 0}, {24, 25, 0}, {3, 4, 0}, {4, 5, 0}, {5, 6, 0}, {6, 26, 0}, {26, 27, 0}, {27, 28, 0}, {28, 29, 0}, {29, 30, 0}, {30, 31, 0}, {31, 32, 0}, {32, 33, 0}, {6, 7, 0}, {7, 8, 0}, {8, 9, 0}, {9, 10, 0}, {10, 11, 0}, {11, 12, 0}, {12, 13, 0}, {13, 14, 0}, {14, 15, 0}, {15, 16, 0}, {16, 17, 0}, {17, 18, 0}};
        for (int c = 0; c < 32; c++) {
            int a = (int) result[c][0];
            int b = (int) result[c][0];
            if (derection(a, b) == 1) {
                result[c][2] = routeinflow(a, b)[7] - routeoutflow(a, b)[7];
            } else {
                result[c][0] = b;
                result[c][1] = a;
                result[c][2] = routeinflow(b, a)[7] - routeoutflow(b, a)[7];
            }
        }
        List<LineWastage> wastages = new ArrayList<>();
        int Len = 32;
        for (int i = 0; i < Len; i++)
            wastages.add(new LineWastage((int) Math.round(result[i][0]), (int) Math.round(result[i][1]), result[i][2]));
        return wastages;
    }

    public static Double[] routee(int i, int j) throws Exception {
        Double result[] = new Double[8];
        for (int c = 0; c < 8; c++) {
            Double[] tempin = routeflow(i, j);
            double[] temp;
            if (tempin[c] > 0) {
                temp = get_carbon_potential_record(i);
                result[c] = temp[c];
            } else {
                temp = get_carbon_potential_record(j);
                result[c] = temp[c];
            }
        }
        return result;
    }

    public static List<LineWastage>
    routewastagerecord(int i, int j) throws Exception {
        Double[] temp = routeflow(i, j);
        Double[] tempin = routeinflow(i, j);
        Double tempout[] = routeoutflow(i, j);
        List<LineWastage> res = new ArrayList<>();
        for (int c = 0; c < 8; c++) {
            LineWastage lineWastage = new LineWastage();
            if (temp[c] > 0) {
                lineWastage.setFrom(i);
                lineWastage.setTo(j);
            } else {
                lineWastage.setFrom(j);
                lineWastage.setTo(i);
            }
            lineWastage.setWastage(tempin[c] - tempout[c]);
            res.add(lineWastage);
        }
        return res;
    }
}
